
package com.ruoyi.pay.service;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.pay.Exception.ChannelException;
import com.ruoyi.pay.channel.IPaymentService;
import com.ruoyi.pay.consts.CS;
import com.ruoyi.pay.domain.*;
import com.ruoyi.pay.mapper.PayOrderDivisionRecordMapper;
import com.ruoyi.pay.mapper.PayOrderMapper;
import com.ruoyi.pay.mapper.PayWayMapper;
import com.ruoyi.pay.model.BaseModel;
import com.ruoyi.pay.model.params.NormalMchParams;
import com.ruoyi.pay.msg.ChannelRetMsg;
import com.ruoyi.pay.payway.payOrder.UnifiedOrderRQ;
import com.ruoyi.pay.payway.payOrder.UnifiedOrderRS;
import com.ruoyi.pay.utils.*;
import com.ruoyi.pay.vo.*;
import com.ruoyi.rabbitMq.model.PayOrderReissueMQ;
import com.ruoyi.rabbitMq.send.IMQSender;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;

/**
 * <p>
 * 支付订单表 服务实现类
 * </p>
 *
 * @author [mybatis plus generator]
 * @since 2021-04-27
 */
@Service
@Slf4j
public class PayOrderService extends ServiceImpl<PayOrderMapper, PayOrder> {

    @Resource
    private PayOrderMapper payOrderMapper;
    @Resource private PayOrderDivisionRecordMapper payOrderDivisionRecordMapper;


    /** 更新订单状态  【订单生成】 --》 【支付中】 **/
    public boolean updateInit2Ing(String payOrderId, PayOrder payOrder){

        PayOrder updateRecord = new PayOrder();
        updateRecord.setState(PayOrder.STATE_ING);

        //同时更新， 未确定 --》 已确定的其他信息。  如支付接口的确认、 费率的计算。
        updateRecord.setIfCode(payOrder.getIfCode());
        updateRecord.setWayCode(payOrder.getWayCode());
        updateRecord.setMchFeeRate(payOrder.getMchFeeRate());
        updateRecord.setMchFeeAmount(payOrder.getMchFeeAmount());
        updateRecord.setChannelUser(payOrder.getChannelUser());
        updateRecord.setChannelOrderNo(payOrder.getChannelOrderNo());

        return update(updateRecord, new LambdaUpdateWrapper<PayOrder>()
                .eq(PayOrder::getPayOrderId, payOrderId).eq(PayOrder::getState, PayOrder.STATE_INIT));
    }

    /** 更新订单状态  【支付中】 --》 【支付成功】 **/
    public boolean updateIng2Success(String payOrderId, String channelOrderNo, String channelUserId){

        PayOrder updateRecord = new PayOrder();
        updateRecord.setState(PayOrder.STATE_SUCCESS);
        updateRecord.setChannelOrderNo(channelOrderNo);
        updateRecord.setChannelUser(channelUserId);
        updateRecord.setSuccessTime(new Date());

        return update(updateRecord, new LambdaUpdateWrapper<PayOrder>()
                .eq(PayOrder::getPayOrderId, payOrderId).eq(PayOrder::getState, PayOrder.STATE_ING));
    }

    /** 更新订单状态  【支付中】 --》 【订单关闭】 **/
    public boolean updateIng2Close(String payOrderId){

        PayOrder updateRecord = new PayOrder();
        updateRecord.setState(PayOrder.STATE_CLOSED);

        return update(updateRecord, new LambdaUpdateWrapper<PayOrder>()
                .eq(PayOrder::getPayOrderId, payOrderId).eq(PayOrder::getState, PayOrder.STATE_ING));
    }

    /** 更新订单状态  【订单生成】 --》 【订单关闭】 **/
    public boolean updateInit2Close(String payOrderId){

        PayOrder updateRecord = new PayOrder();
        updateRecord.setState(PayOrder.STATE_CLOSED);

        return update(updateRecord, new LambdaUpdateWrapper<PayOrder>()
                .eq(PayOrder::getPayOrderId, payOrderId).eq(PayOrder::getState, PayOrder.STATE_INIT));
    }


    /** 更新订单状态  【支付中】 --》 【支付失败】 **/
    public boolean updateIng2Fail(String payOrderId, String channelOrderNo, String channelUserId, String channelErrCode, String channelErrMsg){

        PayOrder updateRecord = new PayOrder();
        updateRecord.setState(PayOrder.STATE_FAIL);
        updateRecord.setErrCode(channelErrCode);
        updateRecord.setErrMsg(channelErrMsg);
        updateRecord.setChannelOrderNo(channelOrderNo);
        updateRecord.setChannelUser(channelUserId);

        return update(updateRecord, new LambdaUpdateWrapper<PayOrder>()
                .eq(PayOrder::getPayOrderId, payOrderId).eq(PayOrder::getState, PayOrder.STATE_ING));
    }


    /** 更新订单状态  【支付中】 --》 【支付成功/支付失败】 **/
    public boolean updateIng2SuccessOrFail(String payOrderId, Byte updateState, String channelOrderNo, String channelUserId, String channelErrCode, String channelErrMsg){

        if(updateState == PayOrder.STATE_ING){
            return true;
        }else if(updateState == PayOrder.STATE_SUCCESS){
            return updateIng2Success(payOrderId, channelOrderNo, channelUserId);
        }else if(updateState == PayOrder.STATE_FAIL){
            return updateIng2Fail(payOrderId, channelOrderNo, channelUserId, channelErrCode, channelErrMsg);
        }
        return false;
    }

    /** 查询商户订单 **/
    public PayOrder queryMchOrder(String mchNo, String payOrderId, String mchOrderNo){

        if(StringUtils.isNotEmpty(payOrderId)){
            return getOne(PayOrder.gw().eq(PayOrder::getMchNo, mchNo).eq(PayOrder::getPayOrderId, payOrderId));
        }else if(StringUtils.isNotEmpty(mchOrderNo)){
            return getOne(PayOrder.gw().eq(PayOrder::getMchNo, mchNo).eq(PayOrder::getMchOrderNo, mchOrderNo));
        }else{
            return null;
        }
    }


    public Map payCount(String mchNo, Byte state, Byte refundState, String dayStart, String dayEnd) {
        Map param = new HashMap<>();
        if (state != null) {
            param.put("state", state);
        }
        if (refundState != null) {
            param.put("refundState", refundState);
        }
        if (StrUtil.isNotBlank(mchNo)) {
            param.put("mchNo", mchNo);
        }
        if (StrUtil.isNotBlank(dayStart)) {
            param.put("createTimeStart", dayStart);
        }
        if (StrUtil.isNotBlank(dayEnd)) {
            param.put("createTimeEnd", dayEnd);
        }
        return payOrderMapper.payCount(param);
    }

    public List<Map> payTypeCount(String mchNo, Byte state, Byte refundState, String dayStart, String dayEnd) {
        Map param = new HashMap<>();
        if (state != null) {
            param.put("state", state);
        }
        if (refundState != null) {
            param.put("refundState", refundState);
        }
        if (StrUtil.isNotBlank(mchNo)) {
            param.put("mchNo", mchNo);
        }
        if (StrUtil.isNotBlank(dayStart)) {
            param.put("createTimeStart", dayStart);
        }
        if (StrUtil.isNotBlank(dayEnd)) {
            param.put("createTimeEnd", dayEnd);
        }
        return payOrderMapper.payTypeCount(param);
    }

    /** 更新订单为 超时状态 **/
    public Integer updateOrderExpired(){

        PayOrder payOrder = new PayOrder();
        payOrder.setState(PayOrder.STATE_CLOSED);

        return baseMapper.update(payOrder,
                PayOrder.gw()
                        .in(PayOrder::getState, Arrays.asList(PayOrder.STATE_INIT, PayOrder.STATE_ING))
                        .le(PayOrder::getExpiredTime, new Date())
        );
    }

    /** 更新订单 通知状态 --> 已发送 **/
    public int updateNotifySent(String payOrderId){
        PayOrder payOrder = new PayOrder();
        payOrder.setNotifyState(CS.YES);
        payOrder.setPayOrderId(payOrderId);
        return baseMapper.updateById(payOrder);
    }






    /**
    *  计算支付订单商家入账金额
    * 商家订单入账金额 （支付金额 - 手续费 - 退款金额 - 总分账金额）
    * @author syf
    * @site
    * @date 2021/8/26 16:39
    */
    public Long calMchIncomeAmount(PayOrder dbPayOrder){

        //商家订单入账金额 （支付金额 - 手续费 - 退款金额 - 总分账金额）
        Long mchIncomeAmount = dbPayOrder.getAmount() - dbPayOrder.getMchFeeAmount() - dbPayOrder.getRefundAmount();

        //减去已分账金额
        mchIncomeAmount -= payOrderDivisionRecordMapper.sumSuccessDivisionAmount(dbPayOrder.getPayOrderId());

        return mchIncomeAmount <= 0 ? 0 : mchIncomeAmount;

    }

    /**
     * 通用列表查询条件
     * @param iPage
     * @param payOrder
     * @param paramJSON
     * @param wrapper
     * @return
     */
    public TableDataInfo<PayOrder> listByPage(PageQuery pageQuery, PayOrder payOrder, JSONObject paramJSON, LambdaQueryWrapper<PayOrder> wrapper) {
        if (StringUtils.isNotEmpty(payOrder.getPayOrderId())) {
            wrapper.eq(PayOrder::getPayOrderId, payOrder.getPayOrderId());
        }
        if (StringUtils.isNotEmpty(payOrder.getMchNo())) {
            wrapper.eq(PayOrder::getMchNo, payOrder.getMchNo());
        }
        if (StringUtils.isNotEmpty(payOrder.getIsvNo())) {
            wrapper.eq(PayOrder::getIsvNo, payOrder.getIsvNo());
        }
        if (payOrder.getMchType() != null) {
            wrapper.eq(PayOrder::getMchType, payOrder.getMchType());
        }
        if (StringUtils.isNotEmpty(payOrder.getWayCode())) {
            wrapper.eq(PayOrder::getWayCode, payOrder.getWayCode());
        }
        if (StringUtils.isNotEmpty(payOrder.getMchOrderNo())) {
            wrapper.eq(PayOrder::getMchOrderNo, payOrder.getMchOrderNo());
        }
        if (payOrder.getState() != null) {
            wrapper.eq(PayOrder::getState, payOrder.getState());
        }
        if (payOrder.getNotifyState() != null) {
            wrapper.eq(PayOrder::getNotifyState, payOrder.getNotifyState());
        }
        if (StringUtils.isNotEmpty(payOrder.getAppId())) {
            wrapper.eq(PayOrder::getAppId, payOrder.getAppId());
        }
        if (payOrder.getDivisionState() != null) {
            wrapper.eq(PayOrder::getDivisionState, payOrder.getDivisionState());
        }
        if (paramJSON != null) {
            if (StringUtils.isNotEmpty(paramJSON.getString("createdStart"))) {
                wrapper.ge(PayOrder::getCreateTime, paramJSON.getString("createdStart"));
            }
            if (StringUtils.isNotEmpty(paramJSON.getString("createdEnd"))) {
                wrapper.le(PayOrder::getCreateTime, paramJSON.getString("createdEnd"));
            }
        }
        // 三合一订单
        if (paramJSON != null && StringUtils.isNotEmpty(paramJSON.getString("unionOrderId"))) {
            wrapper.and(wr -> {
                wr.eq(PayOrder::getPayOrderId, paramJSON.getString("unionOrderId"))
                        .or().eq(PayOrder::getMchOrderNo, paramJSON.getString("unionOrderId"))
                        .or().eq(PayOrder::getChannelOrderNo, paramJSON.getString("unionOrderId"));
            });
        }

        wrapper.orderByDesc(PayOrder::getCreateTime);
        Page<PayOrder> page = baseMapper.selectPage(pageQuery.build(), wrapper);
        return TableDataInfo.build(page);
    }

    //-------------------------------------下单接口------------------------------------------
    @Autowired
    private MchPayPassageService mchPayPassageService;
    @Autowired private ConfigContextQueryService configContextQueryService;
    @Autowired private PayOrderProcessService payOrderProcessService;
    @Autowired private IMQSender mqSender;
    @Autowired
    protected RequestKitBean requestKitBean;
    @Resource
    private PayWayMapper payWayService;
    @Autowired private ValidateService validateService;



    //新建订单模式 payOrder == null
    public ApiRes unifiedOrder(String wayCode, UnifiedOrderRQ bizRQ){
        return unifiedOrder(wayCode, bizRQ, null);
    }

    /** 统一下单 (新建订单模式) **/
    public ApiRes unifiedOrder(String wayCode, UnifiedOrderRQ bizRQ, PayOrder payOrder){

        // 响应数据
        UnifiedOrderRS bizRS = null;

        //是否新订单模式 [  一般接口都为新订单模式，  由于QR_CASHIER支付方式，需要先 在DB插入一个新订单， 导致此处需要特殊判断下。 如果已存在则直接更新，否则为插入。  ]
        boolean isNewOrder = payOrder == null;
        try {
            //当订单存在时，封装公共参数。
//            if (!isNewOrder) {
//                if (payOrder.getState() != PayOrder.STATE_INIT) {
//                    throw new ServiceException("订单状态异常");
//                }
//                payOrder.setWayCode(wayCode); // 需要将订单更新 支付方式
//                payOrder.setChannelUser(bizRQ.getChannelUserId()); //更新渠道用户信息
//                bizRQ.setMchNo(payOrder.getMchNo());
//                bizRQ.setAppId(payOrder.getAppId());
//                bizRQ.setMchOrderNo(payOrder.getMchOrderNo());
//                bizRQ.setWayCode(wayCode);
//                bizRQ.setAmount(payOrder.getAmount());
//                bizRQ.setCurrency(payOrder.getCurrency());
//                bizRQ.setClientIp(payOrder.getClientIp());
//                bizRQ.setSubject(payOrder.getSubject());
//                bizRQ.setNotifyUrl(payOrder.getNotifyUrl());
//                bizRQ.setReturnUrl(payOrder.getReturnUrl());
//                bizRQ.setChannelExtra(payOrder.getChannelExtra());
//                bizRQ.setExtParam(payOrder.getExtParam());
//                bizRQ.setDivisionMode(payOrder.getDivisionMode());
//            }

            String mchNo = bizRQ.getMchNo();
            String appId = bizRQ.getAppId();

            // 只有新订单模式，进行校验
            if(isNewOrder){
                Long  mchOrderCount= payOrderMapper.selectCount(PayOrder.gw().eq(PayOrder::getMchNo, mchNo).eq(PayOrder::getMchOrderNo, bizRQ.getMchOrderNo()));
                if (mchOrderCount > 0) {
                    throw new ServiceException("商户订单["+bizRQ.getMchOrderNo()+"]已存在");
                }
            }

            if(StringUtils.isNotEmpty(bizRQ.getNotifyUrl()) && !StringKit.isAvailableUrl(bizRQ.getNotifyUrl())){
                throw new ServiceException("异步通知地址协议仅支持http:// 或 https:// !");
            }
            if(StringUtils.isNotEmpty(bizRQ.getReturnUrl()) && !StringKit.isAvailableUrl(bizRQ.getReturnUrl())){
                throw new ServiceException("同步通知地址协议仅支持http:// 或 https:// !");
            }

            //获取支付参数  和 商户信息
            MchAppConfigContext mchAppConfigContext = configContextQueryService.queryMchInfoAndAppInfo(mchNo, appId);
            if(mchAppConfigContext == null){
                throw new ServiceException("获取商户应用信息失败");
            }
            MchInfo mchInfo = mchAppConfigContext.getMchInfo();
            MchApp mchApp = mchAppConfigContext.getMchApp();

            // 根据支付方式， 查询出 该商户 可用的支付接口
            MchPayPassage mchPayPassage = mchPayPassageService.findMchPayPassage(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), wayCode);
            if(mchPayPassage == null){
                throw new ServiceException("商户应用不 支持该支付方式");
            }

            // FIXME 精髓 1、根据支付方式，获取支付接口实现，并检查商户是否可用
            IPaymentService paymentService = checkMchWayCodeAndGetService(mchAppConfigContext, mchPayPassage);

            String ifCode = paymentService.getIfCode();
            //生成订单
            if(isNewOrder){
                //新订单
                payOrder = genPayOrder(bizRQ, mchInfo, mchApp, ifCode, mchPayPassage);
            }

            /*else{
                payOrder.setIfCode(ifCode);

                // 查询支付方式的费率，并 在更新ing时更新费率信息
                payOrder.setMchFeeRate(mchPayPassage.getRate());
                payOrder.setMchFeeAmount(AmountUtil.calPercentageFee(payOrder.getAmount(), payOrder.getMchFeeRate())); //商户手续费,单位分
            }*/
            //调用真是的支付实现类，预先校验（校验不通过返回报错）
            /*String errMsg = paymentService.preCheck(bizRQ, payOrder);
            if(StringUtils.isNotEmpty(errMsg)){
                throw new ServiceException(errMsg);
            }*/

            //自定义订单号
            if(isNewOrder){
                String newPayOrderId = paymentService.customPayOrderId(bizRQ, payOrder, mchAppConfigContext);
                if(StringUtils.isNotBlank(newPayOrderId)){ // 自定义订单号
                    payOrder.setPayOrderId(newPayOrderId);
                }
                //订单入库 订单状态： 生成状态  此时没有和任何上游渠道产生交互。
                payOrderMapper.insert(payOrder);
            }

            // FIXME 精髓 2、调起上游支付接口，真正的支付（返回支付结果）
            bizRS = (UnifiedOrderRS) paymentService.pay(bizRQ, payOrder, mchAppConfigContext);
            //处理上游返回数据，跟新订单状态
            this.processChannelMsg(bizRS.getChannelRetMsg(), payOrder);

            //返回订单数据，并加签
            ApiRes apiRes = packageApiResByPayOrder(bizRQ, bizRS, payOrder);
            return apiRes;
        }  catch (
            ChannelException e) {
            //处理上游返回数据
            this.processChannelMsg(e.getChannelRetMsg(), payOrder);

            if(e.getChannelRetMsg().getChannelState() == ChannelRetMsg.ChannelState.SYS_ERROR ){
                return ApiRes.customFail(e.getMessage());
            }

            return this.packageApiResByPayOrder(bizRQ, bizRS, payOrder);

        } catch (Exception e) {
            log.error("系统异常：{}", e);
            return ApiRes.customFail("系统异常");
        }
    }


    /**
     * <简述>
     * <详细描述>
     * @author syf
     * @date 2025/4/29 23:42
     * @param rq
     * @param mchInfo
     * @param mchApp
     * @param ifCode
     * @param mchPayPassage
     * @return com.ruoyi.pay.domain.PayOrder
     */
    private PayOrder genPayOrder(UnifiedOrderRQ rq, MchInfo mchInfo, MchApp mchApp, String ifCode, MchPayPassage mchPayPassage){

        PayOrder payOrder = new PayOrder();
        payOrder.setPayOrderId(SeqKit.genPayOrderId()); //生成订单ID
        payOrder.setMchNo(mchInfo.getMchNo()); //商户号
        payOrder.setIsvNo(mchInfo.getIsvNo()); //服务商号
        payOrder.setMchName(mchInfo.getMchShortName()); //商户名称（简称）
        payOrder.setMchType(mchInfo.getType()); //商户类型
        payOrder.setMchOrderNo(rq.getMchOrderNo()); //商户订单号
        payOrder.setAppId(mchApp.getAppId()); //商户应用appId
        payOrder.setIfCode(ifCode); //接口代码
        payOrder.setWayCode(rq.getWayCode()); //支付方式
        payOrder.setAmount(rq.getAmount()); //订单金额

        if(mchPayPassage != null){
            payOrder.setMchFeeRate(mchPayPassage.getRate()); //商户手续费费率快照
        }else{
            payOrder.setMchFeeRate(BigDecimal.ZERO); //预下单模式， 按照0计算入库， 后续进行更新
        }

        payOrder.setMchFeeAmount(AmountUtil.calPercentageFee(payOrder.getAmount(), payOrder.getMchFeeRate())); //商户手续费,单位分

        payOrder.setCurrency(rq.getCurrency()); //币种
        payOrder.setState(PayOrder.STATE_INIT); //订单状态, 默认订单生成状态
        payOrder.setClientIp(StringUtils.defaultIfEmpty(rq.getClientIp(), getClientIp())); //客户端IP
        payOrder.setSubject(rq.getSubject()); //商品标题
        payOrder.setBody(rq.getBody()); //商品描述信息
//        payOrder.setChannelExtra(rq.getChannelExtra()); //特殊渠道发起的附件额外参数,  是否应该删除该字段了？？ 比如authCode不应该记录， 只是在传输阶段存在的吧？  之前的为了在payOrder对象需要传参。
        payOrder.setChannelUser(rq.getChannelUserId()); //渠道用户标志
        payOrder.setExtParam(rq.getExtParam()); //商户扩展参数
        payOrder.setNotifyUrl(rq.getNotifyUrl()); //异步通知地址
        payOrder.setReturnUrl(rq.getReturnUrl()); //页面跳转地址

        // 分账模式
        payOrder.setDivisionMode(ObjectUtils.defaultIfNull(rq.getDivisionMode(), PayOrder.DIVISION_MODE_FORBID));

        Date nowDate = new Date();

        //订单过期时间 单位： 秒
        if(rq.getExpiredTime() != null){
            payOrder.setExpiredTime(DateUtil.offsetSecond(nowDate, rq.getExpiredTime()));
        }else{
            payOrder.setExpiredTime(DateUtil.offsetHour(nowDate, 2)); //订单过期时间 默认两个小时
        }

        payOrder.setCreateTime(nowDate); //订单创建时间
        return payOrder;
    }

    /** 获取客户端ip地址 **/
    public String getClientIp() {
        return requestKitBean.getClientIp();
    }



    /**
     * 校验： 商户的支付方式是否可用
     * 返回： 支付接口
     * **/
    private IPaymentService checkMchWayCodeAndGetService(MchAppConfigContext mchAppConfigContext, MchPayPassage mchPayPassage){

        //根据ifCode 实例化支付对象
        String ifCode = mchPayPassage.getIfCode();
        IPaymentService paymentService = SpringBeansUtil.getBean(ifCode + "PaymentService", IPaymentService.class);
        if(paymentService == null){
            throw new ServiceException("无此支付通道接口");
        }
        if(!paymentService.isSupport(mchPayPassage.getWayCode())){
            throw new ServiceException("接口不支持该支付方式");
        }

        if(mchAppConfigContext.getMchType() == MchInfo.TYPE_NORMAL){ //普通商户
            NormalMchParams normalMchParams = configContextQueryService.queryNormalMchParams(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), ifCode);
            if(normalMchParams == null){
                throw new ServiceException("商户应用参数未配置");
            }
        }else if(mchAppConfigContext.getMchType() == MchInfo.TYPE_ISVSUB){ //特约商户
            if(configContextQueryService.queryIsvsubMchParams(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), ifCode) == null){
                throw new ServiceException("特约商户参数未配置");
            }
            if(configContextQueryService.queryIsvParams(mchAppConfigContext.getMchInfo().getIsvNo(), ifCode) == null){
                throw new ServiceException("服务商参数未配置");
            }
        }
        return paymentService;

    }


    /** 处理返回的渠道信息，并更新订单状态
     *  payOrder将对部分信息进行 赋值操作。
     * **/
    private void processChannelMsg(ChannelRetMsg channelRetMsg, PayOrder payOrder){

        //对象为空 || 上游返回状态为空， 则无需操作
        if(channelRetMsg == null || channelRetMsg.getChannelState() == null){
            return ;
        }

        String payOrderId = payOrder.getPayOrderId();

        //明确成功
        if(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS == channelRetMsg.getChannelState()) {

            this.updateInitOrderStateThrowException(PayOrder.STATE_SUCCESS, payOrder, channelRetMsg);

            //订单支付成功，其他业务逻辑
            payOrderProcessService.confirmSuccess(payOrder);

            //明确失败
        }else if(ChannelRetMsg.ChannelState.CONFIRM_FAIL == channelRetMsg.getChannelState()) {

            this.updateInitOrderStateThrowException(PayOrder.STATE_FAIL, payOrder, channelRetMsg);

            // 上游处理中 || 未知 || 上游接口返回异常  订单为支付中状态
        }else if( ChannelRetMsg.ChannelState.WAITING == channelRetMsg.getChannelState() ||
            ChannelRetMsg.ChannelState.UNKNOWN == channelRetMsg.getChannelState() ||
            ChannelRetMsg.ChannelState.API_RET_ERROR == channelRetMsg.getChannelState()

        ){
            this.updateInitOrderStateThrowException(PayOrder.STATE_ING, payOrder, channelRetMsg);

            // 系统异常：  订单不再处理。  为： 生成状态
        }else if( ChannelRetMsg.ChannelState.SYS_ERROR == channelRetMsg.getChannelState()){

        }else{
            throw new ServiceException("ChannelState 返回异常！");
        }

        //判断是否需要轮询查单
        if(channelRetMsg.isNeedQuery()){
            //if(true){
            mqSender.send(PayOrderReissueMQ.build(payOrderId, 1), 5);
            int i = 0;
        }

    }


    /** 更新订单状态 --》 订单生成--》 其他状态  (向外抛出异常) **/
    private void updateInitOrderStateThrowException(byte orderState, PayOrder payOrder, ChannelRetMsg channelRetMsg){

        payOrder.setState(orderState);
        payOrder.setChannelOrderNo(channelRetMsg.getChannelOrderId());
        payOrder.setErrCode(channelRetMsg.getChannelErrCode());
        payOrder.setErrMsg(channelRetMsg.getChannelErrMsg());

        // 聚合码场景 订单对象存在会员信息， 不可全部以上游为准。
        if(StringUtils.isNotEmpty(channelRetMsg.getChannelUserId())){
            payOrder.setChannelUser(channelRetMsg.getChannelUserId());
        }

        this.updateIngAndSuccessOrFailByCreatebyOrder(payOrder, channelRetMsg);

    }


    /***
     *
     * 支付中 --》 支付成功或者失败
     * **/
    @Transactional
    public void updateIngAndSuccessOrFailByCreatebyOrder(PayOrder payOrder, ChannelRetMsg channelRetMsg){

        boolean isSuccess = this.updateInit2Ing(payOrder.getPayOrderId(), payOrder);
        if(!isSuccess){
            log.error("updateInit2Ing更新异常 payOrderId={}", payOrder.getPayOrderId());
            throw new ServiceException("更新订单异常!");
        }

        isSuccess = this.updateIng2SuccessOrFail(payOrder.getPayOrderId(), payOrder.getState(),
            channelRetMsg.getChannelOrderId(), channelRetMsg.getChannelUserId(), channelRetMsg.getChannelErrCode(), channelRetMsg.getChannelErrMsg());
        if(!isSuccess){
            log.error("updateIng2SuccessOrFail更新异常 payOrderId={}", payOrder.getPayOrderId());
            throw new ServiceException("更新订单异常!");
        }
    }


    /** 统一封装订单数据  **/
    private ApiRes packageApiResByPayOrder(UnifiedOrderRQ bizRQ, UnifiedOrderRS bizRS, PayOrder payOrder){

        // 返回接口数据
        bizRS.setPayOrderId(payOrder.getPayOrderId());
        bizRS.setOrderState(payOrder.getState());
        bizRS.setMchOrderNo(payOrder.getMchOrderNo());

        if(payOrder.getState() == PayOrder.STATE_FAIL){
            bizRS.setErrCode(bizRS.getChannelRetMsg() != null ? bizRS.getChannelRetMsg().getChannelErrCode() : null);
            bizRS.setErrMsg(bizRS.getChannelRetMsg() != null ? bizRS.getChannelRetMsg().getChannelErrMsg() : null);
        }

        return ApiRes.okWithSign(bizRS, configContextQueryService.queryMchApp(bizRQ.getMchNo(), bizRQ.getAppId()).getAppSecret());
    }

    /**
     * 获取请求参数并转换为对象，并验证商户信息
     **/
    public  <T extends AbstractRQ> T getRQByWithMchSign(Class<T> cls) {

        //获取请求参数（RequestContextHolder 中保存）
        T bizRQ = getRQ(cls);


        //业务校验， 包括： 验签， 商户状态是否可用， 是否支持该支付方式下单等。
        AbstractMchAppRQ abstractMchAppRQ = (AbstractMchAppRQ) bizRQ;
        String mchNo = abstractMchAppRQ.getMchNo();
        String appId = abstractMchAppRQ.getAppId();
        String sign = bizRQ.getSign();

        if (StringUtils.isAnyBlank(mchNo, appId, sign)) {
            throw new ServiceException("参数有误！");
        }

        //商户应用支付参数信息
        MchAppConfigContext mchAppConfigContext = configContextQueryService.queryMchInfoAndAppInfo(appId, appId);
        if (mchAppConfigContext == null) {
            throw new ServiceException("商户或商户应用不存在");
        }
        if (mchAppConfigContext.getMchInfo() == null || mchAppConfigContext.getMchInfo().getState() != CS.YES) {
            throw new ServiceException("商户信息不存在或商户状态不可用");
        }
        //商户应用校验
        MchApp mchApp = mchAppConfigContext.getMchApp();
        if (mchApp == null || mchApp.getState() != CS.YES) {
            throw new ServiceException("商户应用不存在或应用状态不可用");
        }
        if (!mchApp.getMchNo().equals(mchNo)) {
            throw new ServiceException("参数appId与商户号不匹配");
        }

        // app创建应用时候生成私钥
        String appSecret = mchApp.getAppSecret();

        // 转换为 JSON
        JSONObject bizReqJSON = (JSONObject) JSONObject.toJSON(bizRQ);
        bizReqJSON.remove("sign");

        //参数+appSecret 重新MD5加签，对比传入的加签结果
        String signRes = JeepayKit.getSign(bizReqJSON, appSecret);
        if (!sign.equalsIgnoreCase(signRes)) {
            throw new ServiceException("验签失败");
        }

        return bizRQ;
    }


    /** 获取请求参数并转换为对象，通用验证  **/
    public <T extends AbstractRQ> T getRQ(Class<T> cls){
        //HttpServletRequest获取参数
        T bizRQ = getObject(cls);
        // [1]. 验证通用字段规则
        validateService.validate(bizRQ);
        return bizRQ;
    }


    public UnifiedOrderRQ buildBizRQ(UnifiedOrderRQ rq) {

        //支付方式  比如： ali_bar
        String wayCode = rq.getWayCode();

        Long aLong = payWayService.selectCount(PayWay.gw().eq(PayWay::getWayCode, wayCode));
        if ( aLong<= 0) {
            throw new ServiceException("不支持的支付方式");
        }

        //转换为 bizRQ
        return rq.buildBizRQ();
    }


    /** 获取对象类型 **/
    public <T> T getObject(Class<T> clazz) {
        /** 获取json格式的请求参数 **/
        JSONObject params = requestKitBean.getReqParamJSON();

        T result = params.toJavaObject(clazz);

        if(result instanceof BaseModel){  //如果属于BaseModel, 处理apiExtVal
            JSONObject resultTemp = (JSONObject) JSON.toJSON(result);
            for (Map.Entry<String, Object> entry : params.entrySet()) {  //遍历原始参数
                if(!resultTemp.containsKey(entry.getKey())){
                    ((BaseModel) result).addExt(entry.getKey(), entry.getValue());
                }
            }
        }

        return result;
    }

}
